springboot实战之自定义注解扫描并动态注册bean

您所在的位置:网站首页 spring boot 启动 注解扫描 springboot实战之自定义注解扫描并动态注册bean

springboot实战之自定义注解扫描并动态注册bean

2024-07-13 11:29| 来源: 网络整理| 查看: 265

前言

在项目开发中,我们可能会有这样的需求,通过注解配合AOP来实现一些业务额外功能,比如鉴权、日志记录等,更甚至我们可能会想通过注解,就可以把bean托管给spring管理,比如通过@service注解等。今天我们就来演示如何通过扫描自定义注解,就可以把bean托管给spring。

bean托管spring具体实现

本示例是通过自定义注解@BingLogService来实现一个既能把bean托管给spring管理,又能实现日志记录的功能。从前言的描述,我们可以知道通过自定义注解把bean托管给spring管理,主要分为两步,第一步:扫描,第二步 注册bean到spring

1、扫描自定义注解

通过定义一个ImportBeanDefinitionRegistrar的实现类,在实现类中可以使用ClassPathBeanDefinitionScanner进行扫描并自动注册,它是ClassPathScanningCandidateComponentProvider的子类,所以还是可以添加相同的TypeFilter,然后通过scanner.scan(basePackages)扫描指定的basePackage下满足条件的Class并注册它们为bean。

代码语言:javascript复制public class BindScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware { private ResourceLoader resourceLoader; private ClassLoader classLoader; private Environment environment; public BindScannerRegistrar() { } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @Override public void setBeanClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } @Override public void setEnvironment(Environment environment) { this.environment = environment; } @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Set basePackages = getBasePackages(importingClassMetadata); ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry); scanner.setResourceLoader(this.resourceLoader); scanner.addIncludeFilter(new AnnotationTypeFilter(BingLogService.class)); } }

2、注册bean到spring

借助BeanDefinition来创建Bean定义并注册到BeanFactory中,BeanDefinition要如何获取?在ImportBeanDefinitionRegistrar的实现类或者BeanDefinitionRegistryPostProcessor都可以找到BeanDefinition。具体注册代码核心代码如下

代码语言:javascript复制private void registerLogService(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata) { try { String className = annotationMetadata.getClassName(); Class beanClazz = Class.forName(className); if (!beanClazz.isAnnotationPresent(BingLogService.class)) { throw new RuntimeException("BingLogService is required!"); } BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClazz); GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition(); definition.getPropertyValues().add("logClz", beanClazz); definition.setBeanClass(LogServiceFactroyBean.class); definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE); String beanId = org.apache.commons.lang3.StringUtils.uncapitalize(beanClazz.getSimpleName()); registry.registerBeanDefinition(beanId, definition); } catch (ClassNotFoundException e) { log.error( "Could not register target class: " + annotationMetadata.getClassName(), e); } }总结

通过上面的步骤就可以实现完成75%带有自动注入到spring的注解,为什么是75%呢,因为ImportBeanDefinitionRegistrar只能通过由其它类import的方式来加载,通常是主启动类或者注解,比如再写一个@EnableBindLog,其代码如下:

代码语言:javascript复制@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(value= BindScannerRegistrar.class)public @interface EnableBindLog { String[] basePackages() default {}; Class[] basePackageClasses() default {};}

在启动类上加上@EnableBindLog注解

参考文档

Spring(33)——ImportBeanDefinitionRegistrar介绍

https://elim.iteye.com/blog/2430132

SpringBoot基础篇Bean之动态注册

https://blog.csdn.net/liuyueyi25/article/details/83244255

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-scan-annotation



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3